////////////////////////////////////////////////////////////////////////////////

#ifndef _SERVER_H_
#include "server.h"
#endif

////////////////////////////////////////////////////////////////////////////////

#ifndef _TIMER_H_
#include "timer.h"
#endif

#ifndef _CLIENTPACKETONSERVER_H_
#include "clientpacketonserver.h"
#endif

#ifndef _SERVERPACKETONSERVER_H_
#include "serverpacketonserver.h"
#endif

#include <SDL/SDL.h>

////////////////////////////////////////////////////////////////////////////////


Server::Server()
{
}


////////////////////////////////////////////////////////////////////////////////


Server::~Server()
{
}


////////////////////////////////////////////////////////////////////////////////


void Server::Start()
{
    // Start network
    m_Network.Start(this);

    // Start engine
    m_Engine.Start(this);

    // Run game
    RunGameLoop();
}


////////////////////////////////////////////////////////////////////////////////


void Server::Receive( const ClientPacketOnServer* _packet )
{
    // Redirect packet to engine
    _packet->VisitServerEngine(&m_Engine);
}


////////////////////////////////////////////////////////////////////////////////


void Server::RunGameLoop()
{
    while ( true )
    {
        ProcessLogic();
        NotifyClients();
        Sleep();
    }
}


////////////////////////////////////////////////////////////////////////////////


void Server::ProcessLogic()
{
    // Logic is processed in engine
    m_Engine.UpdateState();
}


////////////////////////////////////////////////////////////////////////////////


void Server::NotifyClients()
{
    if ( IsItTimeToSendAState() )
    {
        SendStateToAllClients( m_Engine.GetState() );
    }
}


////////////////////////////////////////////////////////////////////////////////


void Server::Sleep()
{
    Timer::Sleep(1);
}


////////////////////////////////////////////////////////////////////////////////


bool Server::IsItTimeToSendAState() const
{
    // Send a packet every 30 ms
    const size_t sendDelay = 30;

    static size_t prevTime = Timer::GetCurrTime();
    size_t currTime = Timer::GetCurrTime();

    if (prevTime + sendDelay < currTime)
    {
        prevTime = currTime;
        return true;
    }
    else
        return false;
}


////////////////////////////////////////////////////////////////////////////////


void Server::Send( const ServerPacketOnServer* _packet )
{
    _packet->VisitServerNetwork(&m_Network);
}


////////////////////////////////////////////////////////////////////////////////


void Server::SendStateToAllClients( const ServerState& _state )
{
    // Get all clients IDs
    IntVec clientIDs = GetClientIDs();

    // Compose server state packet
    ServerStatePacket serverStatePacket(Timer::GetCurrTime(), _state);

    // Send packet to each client
    for (size_t i = 0; i < clientIDs.size(); ++i)
    {
        m_Network.SendServerState(clientIDs[i], serverStatePacket);
    }
}


////////////////////////////////////////////////////////////////////////////////


IntVec Server::GetClientIDs() const
{
    ServerState state = m_Engine.GetState();
    PlayersList::const_iterator it = state.GetPlayers().begin();

    IntVec IDs;
    for (;it != state.GetPlayers().end(); ++it)
        IDs.push_back( it->GetID() );

    return IDs;
}


////////////////////////////////////////////////////////////////////////////////


void Server::Disconnect( int _clientID )
{
    // Remove player from engine
    m_Engine.RemoveClient(_clientID);
}


////////////////////////////////////////////////////////////////////////////////
